//
// Created by Administrator on 2021/4/28.
//
#include <cstring>
#include <iostream>
#include <vector>

using namespace std;
#if 0
//普通构造函数
class MoveDemo{
public:
    MoveDemo(): num(new int(0)){//默认的构造函数
        cout<<"construct"<<endl;
    }

    MoveDemo(const MoveDemo& demo): num(new int(*demo.num)){//复制构造函数
        cout<<"copy construct"<<endl;
    }

    ~MoveDemo(){
        cout<<"class destruct"<<endl;
    }
private:
    int* num;
};

MoveDemo GetDemo(){
    return MoveDemo();
}
#endif

#if 1

class MoveDemo {
   public:
    MoveDemo() : num(new int(0)) {  //默认的构造函数
        cout << "construct" << endl;
    }

    MoveDemo(const MoveDemo& demo) : num(new int(*demo.num)) {  //复制构造函数
        cout << "copy construct" << endl;
    }

    MoveDemo(MoveDemo&& demo) noexcept : num(demo.num) {  //移动构造函数
        demo.num = nullptr;
        cout << "move construct" << endl;
    }

    ~MoveDemo() { cout << "class destruct" << endl; }

    friend ostream& operator<<(ostream& out, MoveDemo& demo);

   private:
    int* num;
};

ostream& operator<<(ostream& out, MoveDemo& demo) {
    out << "num=" << *demo.num;
    return out;
}

#endif

class MyString {
   public:
    static size_t CCtor;
    static size_t MCtor;
    static size_t DCtor;
    static size_t CAsgn;
    static size_t MAsgn;

   public:
    //构造函数
    explicit MyString(const char* cstr = nullptr) {
        DCtor++;
        if (cstr) {
            m_data = new char[strlen(cstr) + 1];
            strcpy(m_data, cstr);
        } else {
            m_data = new char[1];
            *m_data = '\0';
        }
    }

    //拷贝构造函数
    MyString(const MyString& str) {
        CCtor++;
        m_data = new char[strlen(str.m_data) + 1];
        strcpy(m_data, str.m_data);
    }

    //移动构造函数
    MyString(MyString&& str) noexcept : m_data(str.m_data) {
        MCtor++;
        str.m_data = nullptr;
    }

    //拷贝赋值函数，=号重载
    MyString& operator=(const MyString& str) {
        CAsgn++;
        if (this == &str) {
            return *this;
        }
        delete[] m_data;
        m_data = new char[strlen(str.m_data) + 1];
        strcpy(m_data, str.m_data);
        return *this;
    }

    //移动赋值函数，=号重载
    MyString& operator=(MyString&& str) noexcept {
        MAsgn++;
        if (this == &str) {
            return *this;
        }
        delete[] m_data;
        m_data = str.m_data;
        str.m_data = nullptr;
        return *this;
    }

    ~MyString() { delete[] m_data; }

    char* get_c_str() const { return m_data; }

   private:
    char* m_data;
};

size_t MyString::CCtor = 0;
size_t MyString::MCtor = 0;
size_t MyString::CAsgn = 0;
size_t MyString::MAsgn = 0;
size_t MyString::DCtor = 0;

MoveDemo GetDemo() { return MoveDemo(); }

MyString getMyString() { return MyString("hello world"); }

void AcceptRef(const MyString& str) {}

void AcceptRRef(MyString&& str) {}

void AcceptVal(MyString str) {}

void Swap(MyString& a, MyString& b) {
    //这里是调用了移动构造函数
    MyString temp = move(a);

    //这两个是移动赋值函数
    a = move(b);
    b = move(temp);
}

void printResult() {
    cout << "DCtor=" << MyString::DCtor << endl;
    cout << "CCtor=" << MyString::CCtor << endl;
    cout << "MCtor=" << MyString::MCtor << endl;
    cout << "CAsgn=" << MyString::CAsgn << endl;
    cout << "MAsgn=" << MyString::MAsgn << endl;
}

#define TEST 5
int main() {
#if TEST == 1
    MoveDemo demo1 = GetDemo();
    MoveDemo demo2((MoveDemo()));
    cout << demo2 << endl;
#endif

#if TEST == 2
    vector<MyString> vecStr;
    vecStr.reserve(1000);
    for (int i = 0; i < 1000; i++) {
        //若没有移动构造函数，这个地方push_back的参数，相当于有一个临时变量a=MyString(MyString("hello"))
        //有移动构造函数的话，直接把MyString("hello")作为右值变量
        vecStr.push_back(MyString("hello"));
    }
    printResult();
#endif

#if TEST == 3
    vector<MyString> vecStr;
    vecStr.reserve(1000);
    for (int i = 0; i < 1000; i++) {
        MyString str("temp");
        vecStr.push_back(move(str));
    }

    printResult();
#endif

#if TEST == 4
    MyString a("a");
    MyString b("b");
    Swap(a, b);
    cout << "a=" << a.get_c_str() << ", b=" << b.get_c_str() << endl;
    printResult();
#endif

#if TEST == 5
    // getMyString()
    // 是个临时对象，右值，如果没有定义移动构造函数，将会走拷贝构造函数
    // getMyString函数体中return的时候，会返回临时对象，也就会调用一次拷贝构造函数
    // getMyString()临时对象作为参数传递给AcceptVal的时候会调用一次拷贝函数
    AcceptVal(getMyString());
    printResult();
#endif

    return 0;
}
